<?php

namespace App\Http\Controllers\api;

use App\Http\Controllers\Controller;
use App\Http\Service\Redisd;
use App\Models\StoreCategory;
use App\Models\StoreProduct;
use App\Models\StoreVisit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;
use Illuminate\Validation\ValidationException;

class ShufflingController extends Controller
{
    protected $goods;

    //轮播图
    public function firstShow()
    {
        $data = StoreProduct::where('is_good',1)->select('slider_image','id')->limit(5)->get();
        return parent::success('ok',$data);
    }
    //精品页
    public function firstQuality()
    {
        $length = \request()->input('length');
        if ($length==[]){
            return '没数据了';
        }
        if(Redisd::getInstance()->get($length.'firstQuality')){
            $json = json_encode(Redisd::getInstance()->get($length.'firstQuality'));
            $data = json_decode($json,true);
            foreach ($data as $v){
                $store_name = mb_substr($v['store_name'],0,6);
                $v['store_name'] = $store_name.'...';
            }
            return parent::success('ok',$data);
        }
        $data = StoreProduct::where('is_best',1)->select('image','id','store_name','store_info','price','unit_name')->offset($length)->limit(6)->get();
        foreach ($data as $v){
            $store_name = mb_substr($v['store_name'],0,6);
            $v['store_name'] = $store_name.'...';
        }
        Redis::setex($length.'firstQuality',10,json_encode($data));

        return parent::success('ok',$data);
    }
    //分类
    public function classification($pid = 0)
    {
        $data = StoreCategory::all();
        //定义一个空数组
        $arr = [];
        foreach ($data as $key => $val) {
            if ($val->pid == $pid) {
                $arr[$key] = $val;
                $arr[$key]['child'] = $data['cate_name'];
            }
        }
        return $arr;
    }
    /**
     * 头部选项卡名称，唯一标识符
     * @return array|\Illuminate\Http\JsonResponse
     */
    public function getHeadTab()
    {
        $cateName = [
            'id',
            'cate_name',
        ];
        $data = StoreCategory::select($cateName)->where('is_show', 0)->get();
        if ($data) {
            return self::success('ok', $data);
        } else {
            return self::error('error', []);
        }
    }

    /**
     * 二级分类
     * @return mixed
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function getHeadTwo()
    {
        $id = intval(\request()->post('id'));

        $data = StoreCategory::where('id',$id)->select();
        if ($data) {
            return self::success('ok', $data);
        } else {
            return self::error('error', []);
        }
    }

    /**
     * 首页对应分类信息
     * @param
     * @return array|\Illuminate\Http\JsonResponse
     */
    public function getTabList(Request $request)
    {

        $cate_id = request()->input('cate_id');

        //调用模型层方法

        if(Redisd::getInstance()->get($cate_id.'firstQuality')){
            $json = json_encode(Redisd::getInstance()->get($cate_id.'firstQuality'));
            $tabList = json_decode($json,true);
            return self::success('ok',$tabList);
        }
        $tabList = StoreCategory::select('$cate_id');
        foreach ($tabList as $v){
            $store_name = mb_substr($v['store_name'],0,6);
            $v['store_name'] = $store_name.'...';
        }
        Redis::setex($cate_id.'firstQuality',10,json_encode($tabList));

        return self::error('error', '');
    }
    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * 曼哈顿算法
     */
    public function Manhattans(Request $request)
    {
        $uid = $request->input('uid');
        if (count(StoreVisit::where('uid',$uid)->get()) == 0){//判断该用户有没有浏览记录
            return self::error('error','该用户暂时没有浏览记录');
        }
        $users = [];
        $last = [];
        $users_data = StoreVisit::get()->groupBy('uid');//根据用户分组
        foreach ($users_data as $k=>$v){//循环处理数组
            foreach ($v as $v_v){
                $last[$v_v['product_id']] = $v_v['count'];
            }
            $users[$k] = $last;
            unset($last);
        }
        $usersArray = json_decode(json_encode($users), true);//转换格式
//        return $usersArray;
        $recommend = $this->recommend($uid, $usersArray);
        if (empty($recommend)){
            return self::error('error','无法根据用户习惯推荐商品');
        }
        return self::success('success',$recommend);
    }

    /**
     * @param $username
     * 用户id
     * @param $users
     * 用户浏览记录
     * @return array
     * 实现推荐
     */
    public function recommend($username, $users)
    {
        //获得最近用户的name
        $nearest = $this->computeNearestNeighbor($username, $users);
        $nearest = $nearest['0']['user'];
        $recommendations = array();
        //得到最近用户的推荐列表
        $neighborRatings = $users[$nearest];
//        return $neighborRatings;
        if ($this->checkArray($neighborRatings)) {
            $usernameAction = $users[$username];
            foreach ($neighborRatings as $name => $code) {
                //读取自己没有的
                if (!isset($usernameAction[$name])) {
                    $recommendations[] = ['goods' => $name, 'count' => $code];
                }
            }
        }
        $this->sortArrByField($recommendations, 'count', true);
        return $recommendations;
    }

    /**
     * @param $first
     * 第一个坐标点
     * @param $last
     * 第二个坐标点
     * @return float|int
     * 计算曼哈顿距离
     */
    private function manhattan($first, $last)
    {
        //曼哈顿值
        $distance = 0;
        if ($this->checkArray($first)) {//判断是否为数组
            foreach ($first as $name => $valuefirst) {
                if (isset($last[$name])) {
                    $valuelast = $last[$name];
                    $distance += abs($valuefirst - $valuelast);//两点的坐标值相减取绝对值后相加
                }
            }
        } else {
            $distance = -1;
        }
        return $distance;
    }

    /**
     * @param $username
     * 用户id
     * @param $users
     * 用户浏览数据
     * @return array
     * 返回最近距离用户
     */
    private function computeNearestNeighbor($username, $users)
    {
        try {
            $distances = [];
            if ($this->checkArray($users)) {//检查是否为数组
                foreach ($users as $key => $user) {
                    if ($key == $username) {
                        continue;
                    }
                    $distance = $this->manhattan($user, $users[$username]);
                    $data = array(
                        'user' => $key,
                        'distance' => $distance,
                    );
                    $distances[] = $data;
                }
            }
            $this->sortArrByField($distances, 'distance', false);
            return $distances;
        }catch (\Dotenv\Exception\ValidationException $validationException){
            return $validationException->getMessage();
        }

    }

    /**
     * @param $array
     * @return bool
     * 检查数组有效性
     */
    private function checkArray($array)
    {
        if (is_array($array) && count($array) > 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @param $array
     * @param $field
     * @param bool $desc
     * 根据数组的某个值将用户“亲密度”进行排序
     */
    private function sortArrByField(&$array, $field, $desc = false)
    {
        $fieldArr = [];
        foreach ($array as $k => $v) {
            $fieldArr[$k] = $v[$field];
        }
        $sort = $desc == false ? SORT_ASC : SORT_DESC;
        array_multisort($fieldArr, $sort, $array);
    }
}
